using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace AppToolKit.Core
{
	public static class DynamicProxyBuilder
	{
		private static AssemblyBuilder dynamicAssembly = null;
		private static ModuleBuilder moduleBuilder = null;
		private static Dictionary<string, Type> typeList = new Dictionary<string, Type>();
		public static InterfaceType GetProxyObject<InterfaceType, BaseType>()
		{
			Type typeFromHandle = typeof(InterfaceType);
			Type typeFromHandle2 = typeof(BaseType);
			Type proxyType = DynamicProxyBuilder.GetProxyType(typeFromHandle, typeFromHandle2);
			return (InterfaceType)Activator.CreateInstance(proxyType, new object[]
			{
				Activator.CreateInstance(typeFromHandle2)
			});
		}
		private static Type GetProxyType(Type interfaceType, Type baseType)
		{
			DynamicProxyBuilder.CheckParams(interfaceType, baseType);
			string text = "_dynamicproxy." + baseType.FullName + "Proxy";
			if (!DynamicProxyBuilder.typeList.ContainsKey(text))
			{
				ModuleBuilder dynamicModule = DynamicProxyBuilder.GetDynamicModule();
				TypeBuilder typeBuilder = dynamicModule.DefineType(text, TypeAttributes.Public, typeof(object), new Type[]
				{
					interfaceType
				});
				FieldBuilder fb = typeBuilder.DefineField("_proxyLocalObj", interfaceType, FieldAttributes.Public);
				DynamicProxyBuilder.CreateCtor(baseType, typeBuilder, fb);
				MethodInfo[] methods = interfaceType.GetMethods();
				for (int i = 0; i < methods.Length; i++)
				{
					MethodInfo method = methods[i];
					DynamicProxyBuilder.CreateMethod(baseType, typeBuilder, method, fb);
				}
				DynamicProxyBuilder.typeList.Add(text, typeBuilder.CreateType());
			}
			return DynamicProxyBuilder.typeList[text];
		}
		private static void CreateMethod(Type baseType, TypeBuilder tb, MethodInfo method, FieldBuilder fb)
		{
			ParameterInfo[] parameters = method.GetParameters();
			Type[] array = new Type[parameters.Length];
			for (int i = 0; i < parameters.Length; i++)
			{
				array[i] = parameters[i].ParameterType;
			}
			MethodInfo method2 = baseType.GetMethod(method.Name, array);
			MethodBuilder methodBuilder = tb.DefineMethod(method.Name, method.Attributes & ~MethodAttributes.Abstract, method.CallingConvention, method.ReturnType, array);
			ILGenerator iLGenerator = methodBuilder.GetILGenerator();
			iLGenerator.EmitWriteLine("Before call");
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldfld, fb);
			for (int i = 1; i <= parameters.Length; i++)
			{
				switch (i)
				{
				case 0:
					iLGenerator.Emit(OpCodes.Ldarg_0);
					break;

				case 1:
					iLGenerator.Emit(OpCodes.Ldarg_1);
					break;

				case 2:
					iLGenerator.Emit(OpCodes.Ldarg_2);
					break;

				case 3:
					iLGenerator.Emit(OpCodes.Ldarg_3);
					break;

				default:
					iLGenerator.Emit(OpCodes.Ldarg_S, i);
					break;
				}
			}
			iLGenerator.Emit(OpCodes.Callvirt, method2);
			iLGenerator.EmitWriteLine("After call");
			iLGenerator.Emit(OpCodes.Ret);
		}
		private static void CreateCtor(Type baseType, TypeBuilder tb, FieldBuilder fb)
		{
			Type type = Type.GetType("System.Object");
			ConstructorInfo constructor = type.GetConstructor(new Type[0]);
			ConstructorBuilder constructorBuilder = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[]
			{
				baseType
			});
			ILGenerator iLGenerator = constructorBuilder.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Call, constructor);
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldarg_1);
			iLGenerator.Emit(OpCodes.Stfld, fb);
			iLGenerator.Emit(OpCodes.Ret);
		}
		private static void CheckParams(Type interfaceType, Type baseType)
		{
			if (!interfaceType.IsInterface)
			{
				throw new Exception();
			}
			bool flag = false;
			Type[] interfaces = baseType.GetInterfaces();
			for (int i = 0; i < interfaces.Length; i++)
			{
				Type type = interfaces[i];
				if (type == interfaceType)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				throw new Exception();
			}
		}
		private static ModuleBuilder GetDynamicModule()
		{
			if (DynamicProxyBuilder.dynamicAssembly == null)
			{
				DynamicProxyBuilder.dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
				DynamicProxyBuilder.moduleBuilder = DynamicProxyBuilder.dynamicAssembly.DefineDynamicModule("MainModule");
			}
			return DynamicProxyBuilder.moduleBuilder;
		}
	}
}
